package com.app.util.common;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.springframework.stereotype.Component;

/**
 * @ClassName: ZipUtils
 * @Description:用于发文文件的复制，和压缩成rar包
 * @company www.suncn.com.cn
 * @date 2017年7月31日 下午2:35:53
 */
@Component
public class ZipUtil {
	File file = null;
	boolean flag = false;
	static final int BUFFER = 8192;
	private static final int BUFFER_SIZE = 2 * 1024;
	
	//======================路径的创建=========文件或文件夹的删除================start================
    /**
     * 创建路径
     * @param strDirPath
     */
    public void initPath(String strDirPath) {
		 String initpath = strDirPath;
	     java.io.File file_dir = new java.io.File(String.valueOf(initpath));
	     if (!file_dir.exists())
	         file_dir.mkdirs();
	} 
     /**  
      *  根据路径删除指定的目录或文件，无论存在与否  
      *@param sPath  要删除的目录或文件  
      *@return 删除成功返回 true，否则返回 false。  
      */  
     public boolean DeleteFolder(String sPath) {   
         flag = false;   
         file = new File(sPath);   
         // 判断目录或文件是否存在   
         if (!file.exists()) {  // 不存在返回 false   
             return flag;   
         } else {   
             // 判断是否为文件   
             if (file.isFile()) {  // 为文件时调用删除文件方法   
                 return deleteFile(sPath);   
             } else {  // 为目录时调用删除目录方法   
                 return deleteDirectory(sPath);   
             }   
         }   
     }
     /**  
      * 删除单个文件  
      * @param   sPath    被删除文件的文件名  
      * @return 单个文件删除成功返回true，否则返回false  
      */  
     public boolean deleteFile(String sPath) {   
         flag = false;   
         file = new File(sPath);   
         // 路径为文件且不为空则进行删除   
         if (file.isFile() && file.exists()) {   
             file.delete();   
             flag = true;   
         }   
         return flag;   
     }
     /**  
      * 删除目录（文件夹）以及目录下的文件  
      * @param   sPath 被删除目录的文件路径  
      * @return  目录删除成功返回true，否则返回false  
      */  
     public boolean deleteDirectory(String sPath) {   
         //如果sPath不以文件分隔符结尾，自动添加文件分隔符   
         if (!sPath.endsWith(File.separator)) {   
             sPath = sPath + File.separator;   
         }   
         File dirFile = new File(sPath);   
         //如果dir对应的文件不存在，或者不是一个目录，则退出   
         if (!dirFile.exists() || !dirFile.isDirectory()) {   
             return false;   
         }   
         flag = true;   
         //删除文件夹下的所有文件(包括子目录)   
         File[] files = dirFile.listFiles();   
         for (int i = 0; i < files.length; i++) {   
             //删除子文件   
             if (files[i].isFile()) {   
                 flag = deleteFile(files[i].getAbsolutePath());   
                 if (!flag) break;   
             } //删除子目录   
             else {   
                 flag = deleteDirectory(files[i].getAbsolutePath());   
                 if (!flag) break;   
             }   
         }   
         if (!flag) return false;   
         //删除当前目录   
         if (dirFile.delete()) {   
             return true;   
         } else {   
             return false;   
         }   
     }
     //======================路径的创建=========文件或文件夹的删除================end================
	//文件复制 ***
    public void copyfile(String filename, String topath)//文件名，复制到
    {
        File tofile = null;
        File myfile = null;
        FileInputStream inStream = null;
        try {
            tofile = new File(topath);
            if (!tofile.exists())
                tofile.createNewFile();
            myfile = new File(filename);
            if (!myfile.exists()){
                myfile.createNewFile();
            }
            inStream = new FileInputStream(myfile);
        } catch (Exception e) {
            System.out.print(e);
        }
        try {
            BufferedOutputStream outStream = new BufferedOutputStream(new FileOutputStream(tofile));
            BufferedInputStream bin = new BufferedInputStream(inStream);
            byte[] buffer = new byte[1024];
            int m;
            while ((m = inStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, m);             // write strToken to file
            }
            outStream.close();
            bin.close();
            inStream.close();
        } catch (IOException e) {
            System.out.print(e);
        } 
    }
    //======================压缩=========================start================
//	private static void compress(File file, ZipOutputStream out, String basedir) {
//		/* 判断是目录还是文件 */
//		if (file.isDirectory()) {
//			// System.out.println("压缩：" + basedir + file.getName());
//			compressDirectory(file, out, basedir);
//		} else {
//			// System.out.println("压缩：" + basedir + file.getName());
//			compressFile(file, out, basedir);
//		}
//	}
	/** 压缩一个目录 */
//	private static void compressDirectory(File dir, ZipOutputStream out, String basedir) {
//		if (!dir.exists())
//			return;
//
//		File[] files = dir.listFiles();
//		for (int i = 0; i < files.length; i++) {
//			/* 递归 */
//			compress(files[i], out, basedir + dir.getName() + "/");
//		}
//	}
	/** 压缩一个文件 */
	private static void compressFile(File file, ZipOutputStream out, String basedir) {
		if (!file.exists()) {
			return;
		}
		try {
			BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
			ZipEntry entry = new ZipEntry(basedir + file.getName());
			out.putNextEntry(entry);
			int count;
			byte data[] = new byte[BUFFER];
			while ((count = bis.read(data, 0, BUFFER)) != -1) {
				out.write(data, 0, count);
			}
			bis.close();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
//	public static void zip(String srcPathName, String zipFileName) {
//		File file = new File(srcPathName);
//		File zipFile = new File(zipFileName);
//		if (!file.exists())
//			throw new RuntimeException(srcPathName + "不存在！");
//		try {
//			FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
//			CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream, new CRC32());
//			ZipOutputStream out = new ZipOutputStream(cos);
//			// out.setEncoding(System.getProperty("sun.jnu.encoding"));//设置文件名编码方式
//			String basedir = "";
//			compress(file, out, basedir);
//			out.close();
//		} catch (Exception e) {
//			throw new RuntimeException(e);
//		}
//	}
	
	/**
     * 压缩成ZIP
     * @param srcFilePath 压缩文件路径
     * @param tarFilePath 目标ZIP输出路径
     * @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
     *            false:所有文件跑到压缩包根目录下(注意：不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws Exception 压缩失败会抛出异常
     */
    public boolean toZip(String srcFilePath, String tarFilePath, boolean KeepDirStructure) throws Exception {
        boolean isCompressSuccess = false;
        long start = System.currentTimeMillis();
        FileOutputStream fos = null;
        ZipOutputStream zos = null;
        try {
            File sourceFile = new File(srcFilePath);
            if (!sourceFile.exists()) {
                throw new FileNotFoundException("待压缩文件 [" + srcFilePath + "]不存在.");
            }
            fos = new FileOutputStream(new File(tarFilePath));
            zos = new ZipOutputStream(fos);
            // 设置压缩的编码，解决压缩路径中的中文乱码问题
//            zos.setEncoding("UTF-8");
            //zos.setEncoding("GBK");
            compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure);
            isCompressSuccess = true;
            long end = System.currentTimeMillis();
            System.out.println("【文件压缩】 压缩完成，耗时：{} ms"+(end - start));
        } catch (Exception e) {
        	System.out.println("【文件压缩】 压缩失败"+ e);
            throw new RuntimeException("文件压缩失败", e);
        } finally {
            closeOutPutStream(zos);
            closeOutPutStream(fos);
        }
        return isCompressSuccess;
    }
    
    /**
     * 递归压缩方法
     * @param sourceFile 源文件
     * @param zos zip输出流
     * @param name 压缩后的名称
     * @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
     *            false:所有文件跑到压缩包根目录下(注意：不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws Exception
     */
    private void compress(File sourceFile, ZipOutputStream zos, String name, boolean KeepDirStructure)
            throws Exception {
        byte[] buf = new byte[BUFFER_SIZE];
        if (sourceFile.isFile()) {
            // 向zip输出流中添加一个zip实体，构造器中name为zip实体的文件的名字
            zos.putNextEntry(new ZipEntry(name));
            // copy文件到zip输出流中
            int len;
            FileInputStream in = new FileInputStream(sourceFile);
            while ((len = in.read(buf)) != -1) {
                zos.write(buf, 0, len);
            }
            zos.closeEntry();
            in.close();
        } else {
            File[] listFiles = sourceFile.listFiles();
            if (listFiles == null || listFiles.length == 0) {
                // 需要保留原来的文件结构时,需要对空文件夹进行处理
                if (KeepDirStructure) {
                    // 空文件夹的处理
                    zos.putNextEntry(new ZipEntry(name + "/"));
                    // 没有文件，不需要文件的copy
                    zos.closeEntry();
                }
            } else {
                for (File file : listFiles) {
                    // 判断是否需要保留原来的文件结构
                    if (KeepDirStructure) {
                        // 注意：file.getName()前面需要带上父文件夹的名字加一斜杠,
                        // 不然最后压缩包中就不能保留原来的文件结构,即：所有文件都跑到压缩包根目录下了
                        compress(file, zos, name + "/" + file.getName(), KeepDirStructure);
                    } else {
                        compress(file, zos, file.getName(), KeepDirStructure);
                    }
                }
            }
        }
    }
    //======================压缩=========================end================
    
    /**
     * 释放资源
     * @Title closeOutPutStream
     * @param ops
     * @return void
     */
    public void closeOutPutStream(OutputStream ops) {
        if (ops != null) {
            try {
                ops.close();
            } catch(IOException ex) {
            	System.out.println("关闭输出流失败"+ex);
            }
        }
    }
}
